package com.zz.ecommerce.togatherDeclareMgr.custDeclarationGenerate.service;

import com.zz.bundles.cache.dict.DictTag;
import com.zz.ecommerce.common.bean.jnc.db.declForm.TDeclareFormHeadJn;
import com.zz.ecommerce.common.bean.jnc.db.declForm.TDeclareFormItemJn;
import com.zz.ecommerce.common.constants.TableConstants;
import com.zz.ecommerce.togatherDeclareMgr.common.bean.TCargo;
import com.zz.ecommerce.togatherDeclareMgr.common.bean.TEntryInfo;
import com.zz.ecommerce.togatherDeclareMgr.common.dao.TCargoDao;
import com.zz.ecommerce.togatherDeclareMgr.custDeclarationGenerate.dao.TDeclareFormHeadJnDao;
import com.zz.ecommerce.togatherDeclareMgr.custDeclarationGenerate.dao.TDeclareFormItemJnDao;
import com.zz.ecommerce.togatherDeclareMgr.common.dao.TEntryInfoDao;
import com.zz.ecommerce.user.UserInfo;
import com.zz.ecommerce.utils.BeanMapUtill;
import com.zz.ecommerce.utils.DateUtil;
import com.zz.ecommerce.utils.SessionUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.util.*;

/**
 * Created by admin on 2016/1/14.
 */
@Service
public class CustDeclarationGenerateService {

    @Autowired
    private TDeclareFormHeadJnDao declareFormHeadJnDao;

    @Autowired
    private TDeclareFormItemJnDao declareFormItemJnDao;

    @Autowired
    private TEntryInfoDao entryInfoDao;

    @Autowired
    private TCargoDao cargoDao;

    public String getLongSeq()
    {
        return cargoDao.getLongSeq("SEQ_COMMON");
    }

    public String getELongSeq()
    {
        return cargoDao.getELongSeq("SEQ_COMMON");
    }

    @Transactional
    public void toDeclareCust(List<String> idList) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        List<TDeclareFormHeadJn> declarationHeadList = new ArrayList<TDeclareFormHeadJn>();

        for(int i = 0, size = idList.size(); i < size; i++) {
            String id = idList.get(i);

            TDeclareFormHeadJn declareFormHeadJn = new TDeclareFormHeadJn();
            declareFormHeadJn.setId(id);
            declareFormHeadJn = declareFormHeadJnDao.query(TableConstants.T_DECLARE_FORM_HEAD_JN, declareFormHeadJn);

            if (null == declareFormHeadJn) {
                throw new RuntimeException("申报单流水号:" + id + "查询不到申报单");
            }

            if (StringUtils.isNotEmpty(declareFormHeadJn.getRelateDeclCustId())) {
                throw new RuntimeException("申报单流水号:" + id + "的申报单已经生成报关单，不能再次生成");
            }

            declarationHeadList.add(declareFormHeadJn);
        }

        //1.校验申报单表头是否符合规则
        validateHead(declarationHeadList);

        //2.合并商品列表
        List<TDeclareFormItemJn> declarationGoodsList = mergeGoods(idList);

        //3.保存报关单表头
        TEntryInfo entryInfo = saveHead(declarationHeadList.get(0));

        //4.保存报关单货物列
        saveGoods(entryInfo.getIndx(), declarationGoodsList);

        //5.更新申报单关联字段
        for(TDeclareFormHeadJn head : declarationHeadList)
        {
            updateDeclareFormHead(head.getId(), entryInfo.getIndx());
        }
    }

    private void validateHead(List<TDeclareFormHeadJn> declarationHeadList)
    {
        //总署：同一经营单位、同一运输方式、同一启运国/运抵国、同一进出境口岸
        //口岸：同一电商企业、同一贸易国别、同一主管海关
        Map<String, String> peFlagMap = new HashMap<String, String>();
        Map<String, String> cbeCodeMap = new HashMap<String, String>();
        Map<String, String> countryMap = new HashMap<String, String>();
        Map<String, String> customsCodeMap = new HashMap<String, String>();

        for(TDeclareFormHeadJn head : declarationHeadList)
        {
            String peFlag = StringUtils.defaultString(head.getPeflag());
            String cbeCode = StringUtils.defaultString(head.getCbeCode());
            String coutry = StringUtils.defaultString(head.getCountry());
            String customeCode = StringUtils.defaultString(head.getCustomsCode());

            peFlagMap.put(peFlag, "");
            cbeCodeMap.put(cbeCode, "");
            countryMap.put(coutry, "");
            customsCodeMap.put(customeCode, "");
        }

        if(peFlagMap.size() > 1)
        {
            throw new RuntimeException("不支持邮、快件混合生成报关单");
        }

        if(cbeCodeMap.size() > 1)
        {
            throw new RuntimeException("申报单不是同一家电商企业，不能生成报关单");
        }
        if(countryMap.size() > 1)
        {
            throw new RuntimeException("申报单不是同一贸易国别，不能生成报关单");
        }
        if(customsCodeMap.size() > 1)
        {
            throw new RuntimeException("申报单不是同一主管海关，不能生成报关单");
        }

    }

    private List<TDeclareFormItemJn> mergeGoods(List<String> idList)
    {
        //同一10位海关商品编码、同一申报计量单位、同一法定计量单位、同一币制规则进行归并
        List<TDeclareFormItemJn> declarationGoodsList = new ArrayList<TDeclareFormItemJn>();

        for(int i = 0, size = idList.size(); i < size; i++)
        {
            String id = idList.get(i);
            TDeclareFormItemJn goods = new TDeclareFormItemJn();
            goods.setRelateId(id);
            List<TDeclareFormItemJn> curGoodsList = declareFormItemJnDao.queryAll(TableConstants.T_DECLARE_FORM_ITEM_JN,
                    goods, "");
            declarationGoodsList.addAll(curGoodsList);
        }

        Map<String, TDeclareFormItemJn> mergeGoodsMap = new LinkedHashMap<>();
        for(TDeclareFormItemJn goods : declarationGoodsList)
        {
            String hsCode = StringUtils.defaultString(goods.getHsCode());
            String declUnit = StringUtils.defaultString(goods.getDeclUnit());
            String itemUnit = StringUtils.defaultString(goods.getItemUnit());

            String key = hsCode + "=" + declUnit +  "=" + itemUnit;
            if(!mergeGoodsMap.containsKey(key))
            {
                mergeGoodsMap.put(key, goods);
                continue;
            }

            TDeclareFormItemJn preGoods = mergeGoodsMap.get(key);

            //申报总价
            preGoods.setTotalPrice(add(preGoods.getTotalPrice(), goods.getTotalPrice()));

            //人民币总价
            preGoods.setRmbTotalPrice(add(preGoods.getRmbTotalPrice(), goods.getRmbTotalPrice()));

            //数量
            preGoods.setDeclCount(add(preGoods.getDeclCount(), goods.getDeclCount()));
        }

        if(mergeGoodsMap.size() > 20)
        {
            throw new RuntimeException("归并后的商品条数超过20条，不能生成报关单");
        }

        List<TDeclareFormItemJn> mergeGoodsList = new ArrayList<TDeclareFormItemJn>();

        Collection<TDeclareFormItemJn> values = mergeGoodsMap.values();
        for(TDeclareFormItemJn value : values)
        {
            mergeGoodsList.add(value);
        }
        return mergeGoodsList;
    }

    private String add(String a, String b)
    {
        a = StringUtils.defaultString(a, "0");
        b = StringUtils.defaultString(b, "0");
        return new BigDecimal(a).add(new BigDecimal(b)).toString();
    }

    private TEntryInfo saveHead(TDeclareFormHeadJn declareHead) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Map<String, String> mapper = new HashMap<>();
        //报关流水号
        mapper.put("entryNo","");
        //报/转关类型
        mapper.put("dectransid","");
        mapper.put("dectranscn","");
        //报关单类型
        mapper.put("custypeco","");
        mapper.put("custypecn","");

        //申报地海关
        mapper.put("declarecustomsco","customsCode");
        mapper.put("declarecustoms","");

        //统一编号
        mapper.put("unientryid","");

        //预录入编号
        mapper.put("preentryid","");

        //海关编号
        mapper.put("entryid","");

        //备案号
        mapper.put("manualno","");
        //合同协议号
        mapper.put("contractno","");
        //出口口岸
        mapper.put("portco","");
        mapper.put("portcn","");

        //出口日期
        mapper.put("exImDa","imDate");
        //申报日期
        mapper.put("declareda","");
        //经营单位
        mapper.put("operatorid","");
        mapper.put("operatorcn","");
        //运输方式
        mapper.put("transportco","");
        mapper.put("transportcn","");
        //发货单位
        mapper.put("ownerco","");
        mapper.put("ownerna","");
        //运输工具名称
        mapper.put("conveyance","voy");
        //申报单位
        mapper.put("declareid","declareEnp");
        mapper.put("declarecn","declareName");
        //航次号
        mapper.put("voyageno","");
        //提运单号
        mapper.put("billno","");
        //监管方式
        mapper.put("tradeco", "");
        mapper.put("tradecn","");
        //纳税单位
        mapper.put("paytaxco","");
        mapper.put("paytaxcn","");
        //许可证号
        mapper.put("licenceno","");
        //运抵国(地区)
        mapper.put("nationco","");
        mapper.put("nationcocn","");
        //指运港
        mapper.put("havenco","officeOfDest");
        mapper.put("havencn","");
        //成交方式
        mapper.put("tradetermsco","");
        mapper.put("tradetermscn","");

        //运费
        mapper.put("carriagesy","");
        mapper.put("carriagesysy","");
        mapper.put("carriagesm","");
        mapper.put("carriagecr","");
        mapper.put("carriagecrcn","");

        //征免性质
        mapper.put("dutyco","");
        mapper.put("dutycn","");

        //保费
        mapper.put("insurancesy","");
        mapper.put("insurancesysy","");
        mapper.put("insurancesm","");
        mapper.put("insurancecr","");
        mapper.put("insurancecrcn","");

        //结汇方式
        mapper.put("paymentco","");
        mapper.put("paymentcn","");

        //杂费
        mapper.put("incidentalsy","");
        mapper.put("incidentalsysy","");
        mapper.put("incidentalsm","");
        mapper.put("incidentalcr","");
        mapper.put("incidentalcrcn","");

        //件数
        mapper.put("pieces","count");
        //包装种类
        mapper.put("packageco","wrapType");
        mapper.put("packagecn","");
        //毛重
        mapper.put("gross","totalWeight");
        //净重
        mapper.put("suttle","netWeight");
        //境内货源地
        mapper.put("regionco","");
        mapper.put("regioncn","");
        //备注
        mapper.put("remark", "");

        TEntryInfo entryHead = new TEntryInfo();
        BeanMapUtill.populate(mapper, declareHead, entryHead);

        entryHead.setIndx(getLongSeq());
        entryHead.setConIndx(getELongSeq());
        String ieFlag = declareHead.getImSign();
        entryHead.setEntryty(ieFlag);
        entryHead.setTradeco("9610");


        String entrytycn = "";
        if("I".equals(ieFlag))
        {
            entrytycn = "进口";
        }
        else if("E".equals(ieFlag))
        {
            entrytycn = "出口";
        }
        entryHead.setEntrytycn(entrytycn);
        entryHead.setCreatetime(DateUtil.nowTime());

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        UserInfo user = SessionUtil.getUserInfo(request.getSession());
        entryHead.setAgentco(user.getCompany());
        entryHead.setMaker(user.getLogName());
        entryHead.setStatus("0");

        entryInfoDao.insert("T_ENTRYINFO", entryHead);

        return entryHead;
    }

    private void saveGoods(String conIndx, List<TDeclareFormItemJn> declarationGoodsList) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        for(TDeclareFormItemJn goods : declarationGoodsList)
        {
            Map<String, String> goodsMapper = new HashMap<>();

            goodsMapper.put("model","itemModal");
            goodsMapper.put("memo","");
            goodsMapper.put("cargotaxco","hsCode");
            goodsMapper.put("legalsm","itemCount");
            goodsMapper.put("menorizesign","");
            goodsMapper.put("nationname","");
            goodsMapper.put("bargainto","totalPrice");
            goodsMapper.put("bargainsm","declCount");
            goodsMapper.put("cargocn","itemName");
            goodsMapper.put("quaIndx","");
            goodsMapper.put("bargaincrcn","");
            goodsMapper.put("seconduncn","");
            goodsMapper.put("cargoen","");
            goodsMapper.put("legalun","itemUnit");
            goodsMapper.put("legaluncn","");
            goodsMapper.put("levyco","");
            goodsMapper.put("codeT","");
            goodsMapper.put("codeS","");
            goodsMapper.put("secondsm","");
            goodsMapper.put("serialno","no");
            goodsMapper.put("nationco","");
            goodsMapper.put("manualsn","itemNo");
            goodsMapper.put("purposeco","");
            goodsMapper.put("secondun","");
            goodsMapper.put("levycocn","");
            goodsMapper.put("bargainun","declUnit");
            goodsMapper.put("nationcocn","");
            goodsMapper.put("bargainunname","");
            goodsMapper.put("purposecocn","");
            goodsMapper.put("bargainuncn","");
            goodsMapper.put("manufacturer","");
            goodsMapper.put("bargainprice","unitPrice");
            goodsMapper.put("enyIndx","");
            goodsMapper.put("cargono","goodsNo");
            goodsMapper.put("processfee","");
            goodsMapper.put("bargaincr", "");

            TCargo cargo = new TCargo();
            BeanMapUtill.populate(goodsMapper, goods, cargo);

            cargo.setIndx(getLongSeq());
            cargo.setConIndx(conIndx);
            cargo.setBargainunname(DictTag.getCargoParamVal("S_LAW_UNIT_E", cargo.getBargainun(), "CODE_C", "NAME_C"));
            cargo.setLegaluncn(DictTag.getCargoParamVal("S_LAW_UNIT_E", cargo.getLegalun(), "CODE_C", "NAME_C"));
            cargoDao.insert("T_CARGO", cargo);
        }
    }

    public void updateDeclareFormHead(String id, String relateDeclCustId)
    {
        TDeclareFormHeadJn headJn = new TDeclareFormHeadJn();
        headJn.setId(id);
        headJn.setRelateDeclCustId(relateDeclCustId);
        declareFormHeadJnDao.update(TableConstants.T_DECLARE_FORM_HEAD_JN, headJn,
                "  WHERE ID=#{updateObj.id} ");
    }

}
